package cn.geekyspace.scanhive.serial.manager;

import cn.geekyspace.scanhive.serial.receiver.PLCDataReceiver;
import cn.geekyspace.scanhive.utils.UIUpdater;
import com.fazecast.jSerialComm.SerialPort;
import javafx.scene.paint.Color;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * PLC串口管理
 */
@Data
@Slf4j
@Component
public class PLCSerialPortManager {

    // 定义当前连接的串口
    private static SerialPort connectionPort;

    // 注入PLC数据接收处理器
    private final PLCDataReceiver plcDataReceiver;

    // 注入UI更新器
    private final UIUpdater uiUpdater;

    /**
     * 获取本地可用的串口详情名称
     * @return 可用串口的列表（格式：COM1 # 描述信息）
     */
    public List<String> getAvailableSerialPorts() {
        return Arrays.stream(SerialPort.getCommPorts())
                .map(port -> {
                    String systemPortName = port.getSystemPortName(); // 串口号，例如 COM1
                    String descriptiveName = port.getDescriptivePortName(); // 描述信息
                    // 去掉描述中重复的串口号部分，例如 "(COM1)"
                    if (descriptiveName.contains("(" + systemPortName + ")")) {
                        descriptiveName = descriptiveName.replace("(" + systemPortName + ")", "").trim();
                    }
                    return systemPortName + " #" + descriptiveName;
                }).collect(Collectors.toList());
    }

    /**
     * 根据串口名称建立连接
     * @param portName 串口名称（如 "COM3" 或 "/dev/ttyUSB0"）
     * @return 是否连接成功
     */
    public boolean openPort(String portName) {
        // 查找指定名称的串口
        SerialPort targetPort = Arrays.stream(SerialPort.getCommPorts())
                .filter(port -> port.getSystemPortName().equalsIgnoreCase(portName) ||
                        port.getDescriptivePortName().equalsIgnoreCase(portName))
                .findFirst()
                .orElse(null);

        // 检查串口是否存在
        if (targetPort == null) {
            log.error("连接串口 {} 不存在！", portName);
            return false;
        }

        // 尝试打开串口
        if (!targetPort.openPort()) {
            log.error("无法打开串口 {}，可能被占用或权限不足！", portName);
            return false;
        }

        try {
            // 设置串口参数（波特率、数据位、停止位、奇偶校验）
            if (!targetPort.setComPortParameters(9600, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY)) {
                log.error("设置串口参数失败！");
                return false;
            }

            // 设置串口超时时间
            if (!targetPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0)) {
                log.error("设置串口超时失败！");
                return false;
            }

            // 确认串口已成功打开
            if (targetPort.isOpen()) {
                connectionPort = targetPort;
                String successMessage = "PLC连接成功: 串口号 = " + connectionPort.getSystemPortName() + ", 串口描述 = " + connectionPort.getDescriptivePortName();
                log.info(successMessage);
                uiUpdater.setLogMessage(successMessage, Color.GREEN);

                // 启动数据接收
                plcDataReceiver.startReceivingData(targetPort);
                return true;
            }
        } catch (Exception e) {
            log.error("配置串口时发生错误：{}", e.getMessage(), e);
        }

        // 关闭串口以清理资源
        targetPort.closePort();
        log.error("串口 {} 打开失败！", portName);
        return false;
    }

    /**
     * 关闭当前连接的串口
     * @return true 如果关闭成功；false 如果没有打开的串口或关闭失败
     */
    public boolean closePort() {
        if (connectionPort != null && connectionPort.isOpen()) {
            boolean isClosed = connectionPort.closePort();
            if (isClosed) {
                String successMessage = "PLC断开连接: 串口号 = " + connectionPort.getSystemPortName() + ", 串口描述 = " + connectionPort.getDescriptivePortName();
                log.info(successMessage);
                uiUpdater.setLogMessage(successMessage, Color.GREEN);

                connectionPort = null;

                // 停止数据接收
                plcDataReceiver.stopReceivingData();
                return true;
            } else {
                log.warn("PLC串口关闭失败！");
                return false;
            }
        }
        return false;
    }
}
